23. 物流行业数据分析

本章概要

  • 本章安排:先用教学平台内置的物流订单完成固定练习,再用课程数据下载入口提供的中国上市公司与行情数据练习同样的分组、汇总和比较方法。
  • 学习材料:平台订单表中的销售时间、销售区域、货品、交货状况、用户反馈与数量字段。
  • 本章任务:校验正整数数量,按月份、区域和货品汇总数量,并计算带分母的交货与反馈占比。
  • 完成后你将得到:月度数量表、区域/货品交货率表、反馈结构表与附带适用条件的运营结论。
  • 自我检查:核对各组数量之和与清理后的总量是否一致,并确认占比的分母和样本量;若缺少字段、数量格式错误或分母为零,应先改正数据再计算。
  • 拓展练习:把同一字段要求拓展应用到另一份经授权物流快照。

课程目标

通过本案例,你将学会:

  • 使用 Pandas 对物流数据进行清洗与转换
  • 从多个维度分析配送时效性问题
  • 描述不同区域与货品的销量结构
  • 基于用户反馈描述反馈结构,不把反馈直接等同于产品质量
  • 综合分析结果提出业务改进建议

物流数据分析的核心维度

物流行业的数据分析通常围绕四个关键维度展开:

维度 核心指标 分析目标
时效性 按时交货率 配送服务是否达标
反馈 合格/返修/拒货占比与分母 哪些组合需要进一步质检
区域 各区域表现对比 识别薄弱区域
货品 各货品销售与反馈 识别问题货品

数据清洗流程概述

本案例的数据清洗包含以下关键步骤:

  • 删除重复记录drop_duplicates() 保留首次出现的记录
  • 删除缺失值dropna() 删除含缺失值的行
  • 删除无关列drop(columns=['订单行']) 移除无用字段
  • 重置索引reset_index(drop=True) 更新行索引
  • 金额转换:将 ‘万元’ 和 ‘元’ 统一为数值格式
  • 删除异常值:移除销售金额为 0 的记录

数据和结果应怎样使用

  • data_wuliu.csv 用于教学平台固定练习;公开教材中的拓展案例使用课程数据下载入口提供的上市公司基本信息和股票行情文件。
  • 平台练习用于掌握分组汇总方法,不能把其中某个地区、货品或月份的高低直接当作真实行业结论。
  • 建议分析顺序:确认文件、字段、期间和单位→完成分组汇总→手工核对一小部分数据→说明结果及其适用范围。

任务准备|平台任务:物流数据分析完整代码

阶段 学习步骤 应得到什么
1 数据要求 核对文件、期间、字段、单位与授权 数据字典与行数
2 质量检查 检查重复、缺失、类型与金额口径 清洗前后核对表
3 描述聚合 按月份、区域、货品汇总 带样本量的聚合表

任务准备(续)|核对与决策

阶段 学习步骤 应得到什么
4 手工核对 重新计算一小部分数据 差异记录或一致结论
5 解释结果 区分观察结果、待验证假设与后续建议 一条附带适用条件的建议

运行前预测|平台任务:物流数据分析完整代码

  • 输入预测:运行前先写出 datanumber_newdata1data_month 的业务含义、数据类型或取值范围,并判断哪一个输入最可能改变结果。
  • 结果预测:不展开答案,先预测将得到“月份交货状况:”相关结果;同时写出方向、数量级或表格/图形结构。
  • 完成要求:能独立说明本任务从输入到“平台任务:物流数据分析完整代码”结果的关键步骤,原样录入平台代码并得到可核对的运行结果。

⭐ 平台任务:物流数据分析完整代码

展开完整代码(投影默认折叠)
# 注:data_wuliu.csv数据文件本地没有,但平台已经内置
# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
import os  # 导入操作系统接口模块
import pandas as pd  # 导入Pandas数据分析库
import numpy as np  # 导入NumPy数值计算库
import matplotlib.pyplot as plt  # 导入Matplotlib绘图库
plt.rcParams['font.sans-serif'] = 'SimHei' ## 设置中文显示

## 数据清洗部分
data = pd.read_csv('data_wuliu.csv',encoding='gbk')

#删除重复记录
data.drop_duplicates(keep='first',inplace=True) #keep='first'默认值,保留第一次出现的重复记录
#删除缺失值
data.dropna(axis=0,how='any',inplace=True) 
#删除订单行
data.drop(columns=['订单行'],inplace=True,axis=1) 
print(data.info())  # 输出数据框基本信息

#更新索引(drop=True:把原来的索引index列删除,重置index)
data.reset_index(drop=True,inplace=True)

def data_deal(number):  # 定义函数data_deal
    if number.find('万元')!= -1:#找到带有万元的,取出数字,去掉逗号,转成float,*10000
        number_new = float(number[:number.find('万元')].replace(',',''))*10000  # 替换数据中的指定值
        pass  # 占位符,暂不执行任何操作
    else: #找到带有元的,删除元,删除逗号,转成float
        number_new = float(number.replace('元','').replace(',',''))  # 替换数据中的指定值
        pass  # 占位符,暂不执行任何操作
    return number_new  # 返回计算结果
data['销售金额'] = data['销售金额'].map(data_deal)  # 对数据进行映射转换
print(data.describe())  # 输出描述性统计信息

#销售金额为0的情况,删除
data = data[data['销售金额']!=0].copy()
data['销售时间'] = pd.to_datetime(data['销售时间'])  # 转换为日期时间格式
data['交货时间'] = pd.to_datetime(data['交货时间'])  # 转换为日期时间格式
data['销售月份'] = data['销售时间'].dt.month  # 提取日期时间属性
data['交货月份'] = data['交货时间'].dt.month  # 提取日期时间属性

#1.配送是否存在问题研究
#月份维度
data['货品交货状况'] = data['货品交货状况'].str.strip() 
data1 = data.groupby(['销售月份','货品交货状况']).size().unstack() #unstack()把行索引变成列索引
data1['按时交货率'] = data1['按时交货']/(data1['按时交货']+data1['晚交货'])  # 提取按时交货列作为data1['按时交货率']变量
print("月份交货状况:\n",data1)  # 输出月份交货状况:\n

data1 = data.groupby(['销售区域','货品交货状况']).size().unstack()  # 按指定列分组聚合
data1['按时交货率'] = data1['按时交货']/(data1['按时交货']+data1['晚交货'])  # 提取按时交货列作为data1['按时交货率']变量
data1 = data1.sort_values(data1.columns[-1],ascending=False)  # 按指定列排序
print("销售区域交货状况:\n",data1)  # 输出销售区域交货状况:\n
#运行后按地区报告样本量与按时率;未核对置信区间和服务目标前不指定优劣地区

#货品维度
data1 = data.groupby(['货品','货品交货状况']).size().unstack()
data1['按时交货率'] = data1['按时交货']/(data1['按时交货']+data1['晚交货'])  # 提取按时交货列作为data1['按时交货率']变量
data1 = data1.sort_values(data1.columns[-1],ascending=False)  # 按指定列排序
print("不同货品交货状况:\n",data1)  # 输出不同货品交货状况:\n
#运行后按货品报告样本量与按时率;未看到实际输出前不指定最低货品

#货品和销售区域结合
data1 = data.groupby(['货品','销售区域','货品交货状况']).size().unstack()
data1['按时交货率'] = data1['按时交货']/(data1['按时交货']+data1['晚交货'])  # 提取按时交货列作为data1['按时交货率']变量
data1 = data1.sort_values(data1.columns[-1],ascending=False)  # 按指定列排序
print("货品和销售区域结合的交货状况:\n",data1)  # 输出货品和销售区域结合的交货状况:\n

#2.是否存在尚有潜力的销售区域问题研究
#月份维度
data_month = data.groupby(['销售月份','货品'])['数量'].sum().unstack()
print("月份维度货品的销售情况:\n",data_month)  # 输出月份维度货品的销售情况:\n

# 绘制各个月份的销售情况
data_month.plot(kind='line',figsize=(12,6))
plt.title('各个月份的销售情况')  # 设置图表标题
plt.savefig("1.png")  # 保存图形至文件
#运行后依据月份×货品聚合表描述峰值;营销或新市场只能列为待验证假设

#销售区域维度
data_region = data.groupby(['销售区域','货品'])['数量'].sum().unstack()
print("销售区域货品的销售情况:\n",data_region)  # 输出销售区域货品的销售情况:\n
#运行后报告区域×货品样本量与销量;未核对成本、时效和对照组前不提出增减投入

#月份和区域结合
data_month_region = data.groupby(['销售月份','销售区域','货品'])['数量'].sum().unstack()
data_month_region['货品2']  # 查看货品2在各月份和区域的销售数量

#交叉表只能定位峰值所在区域;营销归因与加大投入需另设对照验证

#3.商品是否存在质量问题研究
data['货品用户反馈'] = data['货品用户反馈'].str.strip()
data3 = data.groupby(['货品','销售区域'])['货品用户反馈'].value_counts().unstack()  # 按指定列分组聚合
data3['拒货率'] = data3['拒货']/data3.sum(axis=1)  # 计算总和
data3['合格率'] = data3['质量合格']/data3.sum(axis=1)  # 计算总和
data3['返修率'] = data3['返修']/data3.sum(axis=1)  # 计算总和
# 按合格率、返修率、拒货率降序排列以识别质量问题货品
data3.sort_values(['合格率','返修率','拒货率'],ascending=False)
#运行后报告各货品×区域的样本量、合格率、返修率与拒货率;未通过阈值和连续期核对前不作质量或投入结论

任务复盘|平台任务:物流数据分析完整代码

运行后核对:核对 datanumber_newdata1data_month 是否按预测参与运算,实际输出是否与预测一致;若不一致,先检查类型、单位、索引/字段和运算顺序。

拓展练习:只改变一个关键输入或业务场景,先预测输出如何变化,再运行验证并解释变化原因。

数据转换:销售金额标准化

原始数据中销售金额的格式不统一,需要转换为数值类型:

原始格式 转换逻辑 转换结果
'5万元' 提取数字 × 10000 50000.0
'12,345元' 删除逗号和’元’ 12345.0
'1,234.5万元' 删除逗号 × 10000 12345000.0

金额转换函数详解

展开完整代码(投影默认折叠)

def data_deal(number):
    """处理销售金额,统一转换为元(float类型)"""
    if number.find('万元') != -1:
        # 包含'万元':提取数字部分,去逗号,乘以10000
        number_new = float(
            number[:number.find('万元')].replace(',', '')
        ) * 10000
    else:
        # 包含'元':直接去掉'元'和逗号
        number_new = float(
            number.replace('元', '').replace(',', '')
        )
    return number_new

# 使用 map() 将转换函数应用到整列
data['销售金额'] = data['销售金额'].map(data_deal)

日期处理与特征提取

将字符串类型的日期转换为 datetime,并提取月份特征:


# 字符串 → datetime 类型
data['销售时间'] = pd.to_datetime(data['销售时间'])
data['交货时间'] = pd.to_datetime(data['交货时间'])

# 提取月份特征(1-12),用于时间序列分析
data['销售月份'] = data['销售时间'].dt.month
data['交货月份'] = data['交货时间'].dt.month

# 删除销售金额为0的异常记录
data = data[data['销售金额'] != 0].copy()
  • pd.to_datetime() 将字符串解析为日期对象
  • .dt.month 提取月份数值
  • .copy() 创建副本,避免 SettingWithCopyWarning

配送问题分析:分析思路

配送时效性是物流服务的核心 KPI,分析从三个维度切入:

配送问题分析维度 展示月份、区域、货品三个分析维度 按时交货率 月份维度 区域维度 货品维度 识别季节性波动 定位薄弱区域 锁定问题货品

配送分析:月份维度

按月统计按时交货 vs 晚交货的订单数,计算按时交货率:


# 清洗交货状态字段(去除多余空格)
data['货品交货状况'] = data['货品交货状况'].str.strip()

# 按月份和交货状况分组统计
data1 = data.groupby(
    ['销售月份', '货品交货状况']
).size().unstack()

# 计算按时交货率
data1['按时交货率'] = (
    data1['按时交货'] / (data1['按时交货'] + data1['晚交货'])
)
print('月份交货状况:\n', data1)
  • groupby().size() 统计每个分组的记录数
  • unstack() 将行索引转为列索引,形成交叉表

配送分析:区域维度

按销售区域计算按时交货率,并降序排列以快速识别问题区域:


# 按销售区域和交货状况分组统计
data1 = data.groupby(
    ['销售区域', '货品交货状况']
).size().unstack()

# 计算按时交货率
data1['按时交货率'] = (
    data1['按时交货'] / (data1['按时交货'] + data1['晚交货'])
)

# 按按时交货率降序排列
data1 = data1.sort_values(data1.columns[-1], ascending=False)
print('销售区域交货状况:\n', data1)

判读规则(待运行):只有在同期口径、分组样本量足够且缺失率达标时,才把按时率最低地区列入待诊断名单;当前不报告具体地区。

配送分析:货品维度

进一步细分到货品层面,识别哪些货品的配送问题最严重:


# 按货品和交货状况分组
data1 = data.groupby(
    ['货品', '货品交货状况']
).size().unstack()

data1['按时交货率'] = (
    data1['按时交货'] / (data1['按时交货'] + data1['晚交货'])
)
data1 = data1.sort_values(data1.columns[-1], ascending=False)
print('不同货品交货状况:\n', data1)

判读规则(待运行):先报告每种货品的样本量与按时率,再对最低组进行原因分解;未看到实际输出前不指定某一货品。

配送分析:货品 × 区域交叉分析

将货品和区域两个维度结合,精确定位问题组合:


# 多维度交叉分组
data1 = data.groupby(
    ['货品', '销售区域', '货品交货状况']
).size().unstack()

data1['按时交货率'] = (
    data1['按时交货'] / (data1['按时交货'] + data1['晚交货'])
)
data1 = data1.sort_values(data1.columns[-1], ascending=False)
print('货品和销售区域结合的交货状况:\n', data1)

交叉分析能精确定位「哪个货品在哪个区域」出了问题。

销售潜力分析:月度趋势

从月份维度分析各货品的销售数量变化趋势:


# 按月份和货品分组,统计销售数量
data_month = data.groupby(
    ['销售月份', '货品']
)['数量'].sum().unstack()

print('月份维度货品的销售情况:\n', data_month)
  • ['数量'].sum() 对销售数量求和
  • unstack() 将货品从行索引转为列

销售趋势可视化

使用折线图展示各货品销售数量随月份的变化:


# 绘制折线图
data_month.plot(kind='line', figsize=(12, 6))
plt.title('各个月份的销售情况')
plt.xlabel('月份')
plt.ylabel('销售数量')
plt.grid(True, alpha=0.3)
plt.legend(title='货品')
plt.tight_layout()
plt.show()

可验证假设:若某货品在特定月份出现销量峰值,营销投放只是候选解释之一;还需同期活动记录、价格、供给与基线对照才能识别归因。

销售潜力分析:区域维度

分析各货品在不同销售区域的覆盖情况:


# 按销售区域和货品分组统计
data_region = data.groupby(
    ['销售区域', '货品']
)['数量'].sum().unstack()
print('销售区域货品的销售情况:\n', data_region)

待运行输出

  • 输出每个货品覆盖的区域数、销量与观察期,但覆盖少不等于市场空间大。
  • 只有结合市场容量、毛利、服务成本和可比区域后,才能形成扩张假设。

销售潜力分析:月份 × 区域交叉

结合月份和区域,判断货品2销量增长的来源:


# 三维分组:月份 × 区域 × 货品
data_month_region = data.groupby(
    ['销售月份', '销售区域', '货品']
)['数量'].sum().unstack()

# 查看货品2的详细销售数据
data_month_region['货品2']

验证设计:交叉表只能定位“峰值发生在哪个地区”,不能证明营销造成增长。应补充地区×月份的投放、价格与库存记录,再以未投放的可比地区作对照;未通过验证前不增加投入。

质量问题分析:核心指标

基于用户反馈数据,计算三个质量指标:

指标 计算公式 期望方向
合格率 质量合格数 / 总数 越高越好
返修率 返修数 / 总数 越低越好
拒货率 拒货数 / 总数 越低越好

质量分析代码实现

展开完整代码(投影默认折叠)

# 清洗用户反馈字段
data['货品用户反馈'] = data['货品用户反馈'].str.strip()

# 按货品和区域分组,统计各类反馈数量
data3 = data.groupby(
    ['货品', '销售区域']
)['货品用户反馈'].value_counts().unstack()

# 计算三大质量指标
data3['拒货率'] = data3['拒货'] / data3.sum(axis=1)
data3['合格率'] = data3['质量合格'] / data3.sum(axis=1)
data3['返修率'] = data3['返修'] / data3.sum(axis=1)

# 按合格率降序排列
data3 = data3.sort_values(
    ['合格率', '返修率', '拒货率'], ascending=False
)
print(data3)

质量依据检查:先验证再分组

质量依据检查 从样本、口径、核对和行动检查要求四方面检查质量结论 没有输出表,就没有货品排名 样本 货品×区域行数 期间与缺失模式 口径 合格/返修/拒货 分母必须一致 核对 第二人复算子样本 检查连续两期 检查要求 先扩大抽检 再评估投入

配送决策模板:先验证,后试点

  • 观测事实:负责人=物流运营;报告地区×货品样本量、按时率及置信区间。
  • 解释假设:仓库距离、承运商、库存和订单结构可能共同影响时效,不从排名直接推因果。
  • 行动判断条件(课堂假设):以“样本量≥30、连续 4 周低于服务目标 5pp、10% 订单试点”为基准情景;企业应用必须改用已批准 业务规定。
  • 敏感性与停止:并列比较宽松/基准/严格三组阈值;任一情景下客诉或单票成本上升超 3% 即停,每周再次检查,4 周后由运营与财务联合决策。

销售决策边界:峰值不等于营销效果

  • 月度×区域聚合是观测事实;营销、价格、节假日与供货是待验证假设。
  • 营销负责人只可在事先定义的可比地区上做小流量试验,记录增量毛利而非只记销量。
  • 若增量毛利为负、履约率下降超 3pp 或无对照组,立即停止;每个活动周期再次检查。

质量决策边界:抽检先于缩减市场

  • 质量负责人先报告货品×区域样本量、合格/返修/拒货率和质检口径,不用未验证的国家或货品排名做决策。
  • 只在连续两期超过预声明的质量红线时扩大抽检;产品安全事件立即停售并升级,普通波动每月再次检查。
  • 是否减少某一区域的投入,还需要评估成本、服务合同和客户影响;本章的描述性结果不能单独支持这一决定。

本章知识点回顾

技术要点 对应方法
数据清洗 drop_duplicates(), dropna(), str.strip()
数据转换 自定义函数 + map()
日期处理 pd.to_datetime(), .dt.month
分组聚合 groupby().size(), groupby().sum()
交叉分析 unstack(), value_counts()
多列排序 sort_values()
可视化 DataFrame.plot(kind='line')

随堂练习

  • 问题 1|需要准备哪些数据?:销售时间、销售区域、货品、交货状况、用户反馈与数量字段齐全且数量为正整数。
  • 问题 2|需要完成哪些操作?:按月份、区域和货品汇总数量,计算带分母的交货与反馈占比。
  • 问题 3|应得到哪些结果?:月度数量表、区域/货品交货率表、反馈结构表与附带适用条件的运营结论。
  • 问题 4|怎样确认结果可靠?:核对各组数量之和与清理后的总量是否一致,并检查占比的分母和样本量。
  • 问题 5|换一个情境,怎样继续应用?:把同一字段要求拓展应用到另一份经授权物流快照。
  • 作答提示:请依次写清所用数据、分析过程、所得结果、核对方法和拓展思考。课程所需数据见前言中的下载入口;教学平台固定题按页面说明完成。

教师参考解答|答案与说明 1

  • 所用数据与字段:受保护平台物流表仅用于平台练习,不宣称存在本地 case 文件;中国本地解答读取 stock_basic_data.h5/stock_basic_infostock_price_pre_adjusted.h5/data,并标准化为 ts_code/name/industry/area/trade_date/close/vol
  • 平台练习答案|完整聚合函数:直接接受受保护任务中的中文列名;月度、地区、货品和分类反馈占比均由同一快照产生。

教师参考解答|代码 1

展开代码(代码区可独立滚动)
import pandas as pd  # 导入表格库处理平台订单表
import numpy as np  # 导入有限值与整数检查要求工具
def validate_platform_quantities(logistics_orders):  # 定义销售数量质量要求
    required={'销售时间','销售区域','货品','货品交货状况','货品用户反馈','数量'}  # 对齐平台中文字段要求
    if not required<=set(logistics_orders.columns): raise ValueError('输入文件、字段、样本量或数值不符合当前分析要求,请按本页说明检查')  # 缺列时停止
    quantity_numeric=pd.to_numeric(logistics_orders['数量'],errors='coerce')  # 将数量显式解析为数值
    quantity_audit={'missing':int(logistics_orders['数量'].isna().sum())}  # 统计原始缺失数量
    quantity_audit['nonnumeric']=int(logistics_orders['数量'].notna().mul(quantity_numeric.isna()).sum())  # 统计非数字数量
    finite_mask=quantity_numeric.notna()&np.isfinite(quantity_numeric.fillna(0))  # 标记可继续检查的有限值
    quantity_audit['nonfinite']=int(quantity_numeric.notna().mul(~np.isfinite(quantity_numeric.fillna(0))).sum())  # 统计无穷值
    quantity_audit['nonintegral']=int(finite_mask.mul(~np.isclose(quantity_numeric.fillna(0),np.round(quantity_numeric.fillna(0)))).sum())  # 统计非整数
    quantity_audit['nonpositive']=int(finite_mask.mul(quantity_numeric.fillna(0).le(0)).sum())  # 统计非正数量
    quantity_audit['policy']='销售数量必须为正整数;退货须用单独字段记录'  # 记录数量处理规则
    if any(quantity_audit[key] for key in ['missing','nonnumeric','nonfinite','nonintegral','nonpositive']): raise ValueError(f'输入文件、字段、样本量或数值不符合当前分析要求,请按本页说明检查')  # 任一违规即停止
    prepared_orders=logistics_orders.assign(数量=quantity_numeric.astype('int64'))  # 检查要求通过后固定整数类型
    return prepared_orders,quantity_audit  # 返回合格订单与质量检查

教师参考解答|代码 2

展开代码(代码区可独立滚动)
def summarize_platform_logistics(logistics_orders):  # 汇总同一平台订单快照
    prepared_orders,quantity_audit=validate_platform_quantities(logistics_orders)  # 先执行数量质量要求
    required=['销售时间','销售区域','货品','货品交货状况','货品用户反馈','数量']  # 固定聚合字段
    clean_orders=prepared_orders.dropna(subset=required).drop_duplicates().copy()  # 排除关键缺失与完全重复
    if clean_orders.empty: raise ValueError('输入文件、字段、样本量或数值不符合当前分析要求,请按本页说明检查')  # 空样本时停止
    clean_orders['销售时间']=pd.to_datetime(clean_orders['销售时间'])  # 统一销售时间类型
    clean_orders['销售月份']=clean_orders['销售时间'].dt.to_period('M').astype(str)  # 构造月度键
    monthly=clean_orders.groupby('销售月份').agg(rows=('数量','size'),quantity=('数量','sum'))  # 汇总月度行数与销量
    regional=clean_orders.groupby(['销售区域','货品交货状况']).size().unstack(fill_value=0)  # 汇总地区配送状态
    product=clean_orders.groupby(['货品','货品交货状况']).size().unstack(fill_value=0)  # 汇总货品配送状态
    feedback=clean_orders.groupby(['货品','销售区域','货品用户反馈']).size().unstack(fill_value=0)  # 统计分类反馈
    feedback_rate=feedback.div(feedback.sum(axis=1),axis=0)  # 按货品与地区分母计算反馈占比
    if feedback_rate.isna().any().any(): raise ValueError('输入文件、字段、样本量或数值不符合当前分析要求,请按本页说明检查')  # 零分母时停止
    first_region=sorted(clean_orders['销售区域'].astype(str).unique())[0]  # 固定首个地区核对
    region_slice=clean_orders.loc[clean_orders['销售区域'].astype(str).eq(first_region)].groupby('货品')['数量'].sum()  # 独立复算地区货品量
    clean_quantity=clean_orders['数量'].sum()  # 独立计算清洗后总销量
    if clean_quantity!=monthly['quantity'].sum(): raise AssertionError('quantity reconciliation failed')  # 核对月度汇总守恒
    region_quantity=clean_orders.loc[clean_orders['销售区域'].astype(str).eq(first_region),'数量'].sum()  # 独立计算地区总量
    if region_quantity!=region_slice.sum(): raise AssertionError('region quantity reconciliation failed')  # 核对地区分组守恒
    reconciliation={'raw_rows':len(logistics_orders),'clean_rows':len(clean_orders),'clean_quantity':clean_quantity,'region':first_region,'region_quantity':region_quantity}  # 形成检查摘要
    return clean_orders,monthly,regional,product,feedback_rate,region_slice,reconciliation,quantity_audit  # 返回聚合与检查依据

教师参考解答|答案与说明 2

  • 中国本地解答|规定资产完整路线:用长三角物流运输类上市公司月度行情检验“趋势—分组—判断条件”方法;它不是客户订单或货品需求的替代依据。

教师参考解答|代码 3

展开代码(代码区可独立滚动)
from pathlib import Path  # 导入路径工具绑定规定根目录
import pandas as pd  # 导入表格库以读取并标准化HDF字段
import numpy as np  # 导入有限值检查要求工具
root=Path('/home/ubuntu/r2_data_mount/data/stock')  # 指定中国股票数据目录
basic_path=root/'stock_basic_data.h5'  # 绑定公司基础信息HDF快照
price_path=root/'stock_price_pre_adjusted.h5'  # 绑定前复权行情HDF快照
if not basic_path.exists() or not price_path.exists(): raise FileNotFoundError('未找到课程数据文件,请从课程数据下载入口获取并核对文件位置')  # 缺失时如实停止
basic=pd.read_hdf(basic_path,key='stock_basic_info',columns=['order_book_id','symbol','industry_name','province']).rename(columns={'order_book_id':'raw_code','symbol':'name','industry_name':'industry','province':'area'})  # 只读取对象筛选字段并标准化
basic['ts_code']=basic['raw_code'].str.replace('.XSHG','.SH',regex=False).str.replace('.XSHE','.SZ',regex=False)  # 统一证券代码后缀
basic['area']=basic['area'].astype('string').str.replace(r'[省市]$','',regex=True)  # 统一省市简称
required_basic={'ts_code','name','industry','area'}  # 定义基础信息字段要求
if not required_basic<=set(basic.columns): raise ValueError('输入文件、字段、样本量或数值不符合当前分析要求,请按本页说明检查')  # 字段结构 不符时停止
industry_pattern='交通运输|仓储|邮政|快递|道路运输|水上运输|航空运输|装卸搬运|多式联运'  # 排除运输设备制造等非物流运营行业
focus=basic.loc[basic['industry'].str.contains(industry_pattern,na=False) & basic['area'].isin(['上海','江苏','浙江','安徽'])].sort_values('ts_code').head(12)  # 按固定规则选取长三角物流运营公司
if focus.empty: raise ValueError('输入文件、字段、样本量或数值不符合当前分析要求,请按本页说明检查')  # 空对象时停止
focus_raw_codes=focus['raw_code'].tolist()  # 保留HDF原始代码以高效筛选行情
prices=pd.read_hdf(price_path,key='data',where='order_book_id in focus_raw_codes',columns=['close','volume']).reset_index().rename(columns={'order_book_id':'ts_code','date':'trade_date','volume':'vol'})  # 按对象读取并标准化行情字段
prices['ts_code']=prices['ts_code'].str.replace('.XSHG','.SH',regex=False).str.replace('.XSHE','.SZ',regex=False)  # 统一行情证券代码后缀
prices=prices.loc[pd.to_datetime(prices['trade_date']).between('2019-01-01','2025-12-31')].copy()  # 固定观察期,便于比较结果
market=prices.merge(focus[['ts_code','name','area']],on='ts_code',how='inner',validate='many_to_one')  # 合并行情与地区标签

教师参考解答|代码 4

展开代码(代码区可独立滚动)
if focus.empty or market.empty: raise ValueError('输入文件、字段、样本量或数值不符合当前分析要求,请按本页说明检查')  # 空对象或空连接时停止
if not np.isfinite(market[['close','vol']].to_numpy()).all() or market['close'].le(0).any(): raise ValueError('输入文件、字段、样本量或数值不符合当前分析要求,请按本页说明检查')  # 行情必须有限且价格为正
if market.duplicated(['ts_code','trade_date']).any(): raise ValueError('输入文件、字段、样本量或数值不符合当前分析要求,请按本页说明检查')  # 重复键时停止
market['trade_date']=pd.to_datetime(market['trade_date'])  # 统一交易日期
market['month']=market['trade_date'].dt.to_period('M').astype(str)  # 构造月度观察窗
if market['month'].nunique()<6: raise ValueError('输入文件、字段、样本量或数值不符合当前分析要求,请按本页说明检查')  # 期间不足时停止趋势判断
market['return_rate']=market.groupby('ts_code')['close'].pct_change()  # 计算公司日收益率
monthly=market.groupby(['month','area']).agg(companies=('ts_code','nunique'),mean_return=('return_rate','mean'),trading_volume=('vol','sum')).reset_index()  # 输出月度地区聚合
sensitivity=monthly.assign(loose=monthly['mean_return'].abs()>0.02,baseline=monthly['mean_return'].abs()>0.03,strict=monthly['mean_return'].abs()>0.05,threshold_status='课堂情景,待业务规定批准',owner='物流分析负责人',action='核对异常月份',recheck_when='字段发生变化或分母为零',recheck_date='下月第5个工作日')  # 比较三档课堂阈值并绑定说明信息
assert monthly['companies'].gt(0).all()  # 核对每个聚合单元具有明确分母
print(focus[['ts_code','name','area']],monthly,sensitivity)  # 输出对象、聚合与检查要求表

教师参考解答|答案与说明 3

  • 解释答案:物流订单的地区/货品聚合回答运营结构,上市公司行情只提供中国本地的市场代理验证,不能推出订单时效或营销因果;课堂阈值必须换成经负责人批准的 业务规定。
  • 拓展应用答案:平台表恢复时替换函数输入并保留同一快照版本;核对原始/清洗行数与清洗/月度数量守恒,再确认固定地区的逐货品数量之和等于同一地区在清洗表中的总数量。配送状态行数聚合与销量口径不同,不作直接核对。
  • 参考结果:平台练习先说明数量缺失、非数字、非整数和非正数的记录,再给出清洗表、月度/地区/货品汇总、反馈占比和固定地区子样本;公开教材案例给出公司清单和月度×地区比较。所需中国市场数据可从课程数据下载入口取得。
  • 边界 / 局限:课堂阈值须替换为批准 业务规定;聚合不能证明营销因果
  • 常见错误:声称臆造的 case 路径是规定资产;不报分母;把行情代理解释成订单需求